CAN 总线协议是什么
CAN是控制器局域网总线,是一种用于实时应用的串行通讯协议总线,它可以使用双绞线来传输信号,是世界上应用最广泛的现场总线之一。CAN协议用于汽车中各种不同元件之间的通信,以此取代昂贵而笨重的配电线束。该协议的健壮性使其用途延伸到其他自动化和工业应用。CAN协议的特性包括完整性的串行数据通讯、提供实时支持、传输速率高达1Mb/s、同时具有11位的寻址以及检错能力。
CAN总线特征如下:
报文(Message)总线上的数据以不同报文格式发送,但长度受到限制。当总线空闲时,任何一个网络上的节点都可以发送报文。
信息路由(Information Routing)在CAN中,节点不使用任何关于系统配置的报文,比如站地址,由接收节点根据报文本身特征判断是否接收这帧信息。因此系统扩展时,不用对应用层以及任何节点的软件和硬件作改变,可以直接在CAN中增加节点。
标识符(Identifier) 要传送的报文有特征标识符(是数据帧和远程帧的一个域),它给出的不是目标节点地址,而是这个报文本身的特征。信息以广播方式在网络上发送,所有节点都可以接收到。节点通过标识符判定是否接收这帧信息。
数据一致性应确保报文在CAN里同时被所有节点接收或同时不接收,这是配合错误处理和再同步功能实现的。
位传输速率不同的CAN系统速度不同,但在一个给定的系统里,位传输速率是唯一的,并且是固定的。
优先权 由发送数据的报文中的标识符决定报文占用总线的优先权。标识符越小,优先权越高。
远程数据请求(Remote Data Request) 通过发送远程帧,需要数据的节点请求另一节点发送相应的数据。回应节点传送的数据帧与请求数据的远程帧由相同的标识符命名。
仲裁(Arbitration) 只要总线空闲,任何节点都可以向总线发送报文。如果有两个或两个以上的节点同时发送报文,就会引起总线访问碰撞。通过使用标识符的逐位仲裁可以解决这个碰撞。仲裁的机制确保了报文和时间均不损失。当具有相同标识符的数据帧和远程帧同时发送时,数据帧优先于远程帧。在仲裁期间,每一个发送器都对发送位的电平与被监控的总线电平进行比较。如果电平相同,则这个单元可以继续发送,如果发送的是“隐性”电平而监视到的是“显性”电平,那么这个单元就失去了仲裁,必须退出发送状态。
总线状态 总线有“显性”和“隐性”两个状态,“显性”对应逻辑“0”,“隐性”对应逻辑“1”。“显性”状态和“隐性”状态与为“显性”状态,所以两个节点同时分别发送“0”和“1”时,总线上呈现“0”。CAN总线采用二进制不归零(NRZ)编码方式,所以总线上不是“0”,就是“1”。但是CAN协议并没有具体定义这两种状态的具体实现方式。
故障界定(Confinement) CAN节点能区分瞬时扰动引起的故障和永久性故障。故障节点会被关闭。
应答接收节点对正确接收的报文给出应答,对不一致报文进行标记。
CAN通讯距离最大是10公里(设速率为5Kbps),或最大通信速率为1Mbps(设通信距离为40米)。
CAN总线上的节点数可达110个。通信介质可在双绞线,同轴电缆,光纤中选择。
报文是短帧结构,短的传送时间使其受干扰概率低,CAN有很好的校验机制,这些都保证了CAN通信的可靠性。
SOF(帧开始): 通知其他ECU消息进入
CAN-ID: 包含消息的优先级位和ECU的功能地址(就网络而言,CAN-ID就像mac地址一样,但不一样)
RTR: 远程传输请求允许ECU从网络上其他活动的ECU请求消息
控制: 以字节为单位通知数据长度
数据: 包含要通过协议传输的数据值
CRC: 用于错误纠正和数据完整性的循环冗余值
ACK: 表示CRC处理状态
EOF:帧结束标记CAN消息帧的结束
现在,对于网络数据包分析,我们只需要担心 CAN-ID, CONTROL 和 DATA
Wireshark中的CAN总线流量
正如我们在Wireshark中看到的那样,CAN总线是事件驱动的,当ECU通过某些操作(例如,换档,指示器开/关,门锁/解锁等)生成数据时,它会立即在网络上广播,而不会发出任何消息排序。因此,如果我们要查找特定ECU的CAN-ID,则很难通过系统中其他活动ECU生成的数据噪声来查找。幸运的是,Linux获得了名为can-utils的开源软件套件。 16这使我们能够创建用于CAN流量处理和嗅探的网络接口。它具有名为candump的实用程序,可以显示,过滤和记录CAN数据到文件。
设置虚拟CAN网络以进行试验和娱乐
因此,我们大多数人都不敢动手去购买一些硬件并与实际车辆混为一谈,但仍然想知道CAN流量如何实时运行。解决方案是ICSim 16 (用于SocketCAN的仪器集群模拟器)是虚拟CAN网络上的车辆仪表盘数据模拟器。
编译ICSim的步骤git clone https://github.com/zombieCraig/ICSim.git
apt-get install libsdl2-dev libsdl2-image-dev can-utils
cd ICSim && make && ./setup_vcan.sh
使用默认的硬编码CAN-ID启动ICSim
./icsim vcan0
./controls vcan0
现在根据CAN-ID短路更改数据
cansniffer vcan0 #Any CAN interface of your choice
选择控制窗口,然后按向上箭头键提高速度,您会注意到cansniffer输出中的CAN-ID更改值很多,因此CAN-ID用于发动机ECU传输的车辆速度数据。您还可以在Wireshark中捕获该流量并将其保存以备进一步分析。根据源代码文件icsim.c,速度数据的默认仲裁/ CAN-ID为0x244。
Scapy最近增加了对CAN协议层的支持,因此现在您可以在python中进行各种数据分析。下面的基本脚本将来自CAN-ID的所有十六进制值保存在数组中,并找到最小和最大速度。可以使用matplotlib完成更酷的事情,以创建速度数据图,以了解车辆由于道路交通而减速的次数。
from scapy.all import *
import struct
load_layer("can") #Allows us to work with CAN-bus network layer please note that it only works with latest veersion of ScaPy library
can_packets = rdpcap('canbus-traffic-capture.pcap')
CAN_ID = #Your desired CAN-ID for vehicle speed data in hex format
raw_data = []
for x in can_packets:
if x["CAN"].identifier == int(CAN_ID, 16):
data = x["CAN"].data.hex()
raw_data.append(data[10:]) #From traffic analysis we know that speed data only 4-bit long out of 14-bit hex string
raw_data = list(set(raw_data))
print("Raw RPM data in hex: " + str(raw_data))
delta_rpm = []
for y in raw_data:
delta_rpm.append(int(y, 16))